/*
 * Copyright 2019 Web3 Labs Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.web3j.utils;

import java.io.IOException;

import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;

/** Revert reason extraction and retrieval functions. */
public class RevertReasonExtractor {

	public static final String MISSING_REASON = "N/A";

	/**
	 * Extracts the error reason of a reverted transaction (if one exists and
	 * enabled).
	 *
	 * @param transactionReceipt      the reverted transaction receipt
	 * @param data                    the reverted transaction data
	 * @param web3j                   Web3j instance
	 * @param revertReasonCallEnabled flag of reason retrieval via additional call
	 * @return the reverted transaction error reason if exists or null otherwise
	 * @throws IOException if the call to the node fails
	 */
	public static String extractRevertReason(TransactionReceipt transactionReceipt, String data, Web3j web3j,
			Boolean revertReasonCallEnabled) throws IOException {

		if (transactionReceipt.getRevertReason() != null) {
			return transactionReceipt.getRevertReason();
		} else if (revertReasonCallEnabled) {
			String revertReason = retrieveRevertReason(transactionReceipt, data, web3j);
			if (revertReason != null) {
				transactionReceipt.setRevertReason(revertReason);
				return revertReason;
			}
		}
		return MISSING_REASON;
	}

	/**
	 * Retrieves the error reason of a reverted transaction (if one exists).
	 *
	 * @param transactionReceipt the reverted transaction receipt
	 * @param data               the reverted transaction data
	 * @param web3j              Web3j instance
	 * @return the reverted transaction error reason if exists or null otherwise
	 * @throws IOException if the call to the node fails
	 */
	public static String retrieveRevertReason(TransactionReceipt transactionReceipt, String data, Web3j web3j)
			throws IOException {

		if (transactionReceipt.getBlockNumber() == null) {
			return null;
		}
		return web3j
				.ethCall(Transaction.createEthCallTransaction(transactionReceipt.getFrom(), transactionReceipt.getTo(),
						data), DefaultBlockParameter.valueOf(transactionReceipt.getBlockNumber()))
				.send().getRevertReason();
	}
}
